/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package station;

import java.nio.ByteBuffer;

/**
 * zuständig für fachliches event: "Nachricht eingegangen" um alles notwendige
 * zu erneuern
 *
 * @author safe
 */
public class StationUpdateWorker extends Thread {

    private final boolean loggAll;
    private long synchronisierteEmpfangszeit;
    private LoggerThread logger;
    private byte[] message;

    public StationUpdateWorker(long synchronisierterEmpfangszeit, byte[] message) {
        this(synchronisierterEmpfangszeit, message, false);
    }

    public StationUpdateWorker(long synchronisierteEmpfangszeit, byte[] message, boolean loggAll) {
        this.synchronisierteEmpfangszeit = synchronisierteEmpfangszeit;
        this.message = message;
        this.loggAll = loggAll;
    }

    private boolean istAStation(String stationClass) {
        return stationClass.equals("A");
    }

    private void log(String station, String msg) {
        logger = new LoggerThread(station, msg);
        logger.start();
    }

    private String extractMessagePayLoad(byte[] message) {
        byte[] stationInfo = new byte[14];
        System.arraycopy(message, 10, stationInfo, 0, 14);
        return new String(stationInfo);
    }

    private String extractMessageStationType(byte[] message) {
        if (message[24] == 'A') {
            return "A";
        } else if (message[24] == 'B') {
            return "B";
        } else {
            return "";
        }
    }

    private int extractMessageSlotNumber(byte[] message) {
        return (int) message[25];
    }

    private String extractMessageStationName(byte[] message) {
        byte[] stationInfo = new byte[10];
        System.arraycopy(message, 0, stationInfo, 0, 10);
        return new String(stationInfo);
    }

    private long extractMessageForeignSynchronizedSendingTime(byte[] message) {
        ByteBuffer buffer = ByteBuffer.wrap(message);
        return buffer.getLong(26);
    }

    private boolean areWePartOfCollision(String actualStationName) {
        if (actualStationName.equals(DataEmpfangeneNachrichten.getOurStationName())) {
            return true;
        }
        if (DataEmpfangeneNachrichten.getLastMessageStationName().equals(DataEmpfangeneNachrichten.getOurStationName())) {
            return true;
        }
        return false;
    }
    
    @Override
    public void run() {
        int reservedSlotNumber = this.extractMessageSlotNumber(message);

        String stationName = this.extractMessageStationName(message);
        String dataPayLoad = this.extractMessagePayLoad(message);
        String senderStationClass = this.extractMessageStationType(message);

        long foreignSynchronizedSendingTime = this.extractMessageForeignSynchronizedSendingTime(message);


        if (DataEmpfangeneNachrichten.collisionDetect(foreignSynchronizedSendingTime)) {

            manageCollision(reservedSlotNumber, stationName, foreignSynchronizedSendingTime);

        } else {
            
            DataEmpfangeneNachrichten.setLastMessageAsValid(stationName,
                    senderStationClass,
                    reservedSlotNumber,
                    foreignSynchronizedSendingTime,
                    synchronisierteEmpfangszeit);

            if (istAStation(senderStationClass) && !stationName.equals(DataEmpfangeneNachrichten.getOurStationName())) {
 //              System.out.println("Foreign: " +  synchronisierteEmpfangszeit + " unser: "+synchronisierteEmpfangszeit);
//            if (DataAbweichungsZeit.getStationClass().equals("A")) {
                DataAbweichungsZeit.adaptTimeOfStation(foreignSynchronizedSendingTime, synchronisierteEmpfangszeit);
//            } else {
//                // hier lassen wir die differenzzeit zu 100% auf unsere abweichungszeit einwirken
//                DataAbweichungsZeit.setDiffTime(DataAbweichungsZeit.getAbWeichungsZeit() + (timestamps[0] - timestamps[1]));
//            }
            }
        }
        if (loggAll) {
            this.log(stationName, "DATA: " + dataPayLoad + " CLASS: " + senderStationClass + " NEXT SLOT: " + reservedSlotNumber + " EMPFANGSZEIT: " + this.synchronisierteEmpfangszeit + " SENDEZEITPUNKT: " + foreignSynchronizedSendingTime);
        }
    }
    

    private synchronized void manageCollision(int reservedSlotNumber, String stationName, long foreignSynchronizedSendingTime) {
       
        DataSlotBelegung.setSlotFree(reservedSlotNumber);
        
        // gibt es noch eine zwischengespeicherte nachricht - diese ist ab hier ungültig
        if (DataEmpfangeneNachrichten.getLastMessageSlot() != -1) {
            DataSlotBelegung.setSlotFree(DataEmpfangeneNachrichten.getLastMessageSlot());
        }
        
//        if(reservedSlotNumber == DataSlotBelegung.getOurNextSlot()){
//            DataSlotBelegung.disableNextSlot();
//            System.out.println("Kollision durch reservierung");
//        }
        
        // wenn wir selber durch die kollision betroffen sind müssen wir unseren für
        // den nächsten frame reservierten slot zurücknehmen
        if (areWePartOfCollision(stationName)) {
            DataSlotBelegung.disableNextSlot();
        }
        
        DataEmpfangeneNachrichten.collisionCleanUp(foreignSynchronizedSendingTime);
        
    }
}
